﻿#include "AaHead.h"

AaHead::AaHead(AACore *aaCore) : Worker(WorkerName::AaHead)
{
    aaHeadConfig = new AaHeadConfig();
    aaHeadConfigFile
        = new ConfigFile("AaHeadConfig", aaHeadConfig, QString("%1/AaHeadConfig.json").arg(getWorkerConfigDir()));
    aaHeadConfigFile->populate();

    dispenser = new GTDispenser(logCate(), aaHeadConfig->dispenserConfig());
    this->aaCore = aaCore;
}

AaHead::~AaHead() {}

void AaHead::initEventHandle()
{
    sUTXYZ = MotionElementContainer::getIns()->getItem<XYZModule>(XYZModuleName::SUTXYZ);
    aAThetaXYZ = MotionElementContainer::getIns()->getItem<XYZModule>(XYZModuleName::AaHeadTheta);

    shotGlueOut = MotionElementContainer::getIns()->getItem<SCDO>(DoName::ShotGlueOut);
    aaGripper = MotionElementContainer::getIns()->getItem<SCCylinder>(CylName::AAGripper);

    uVOut = MotionElementContainer::getIns()->getItem<SCDO>(DoName::UV1);

    sUTVacuum = MotionElementContainer::getIns()->getItem<SCVacuum>(VacuumName::SUTVacuum);
    lUTVacuum = MotionElementContainer::getIns()->getItem<SCVacuum>(VacuumName::LUTVacuum);
    LUTRejectVacuum = MotionElementContainer::getIns()->getItem<SCVacuum>(VacuumName::LUTRejectVac);

    shotGlueDotPrLocation = VisionManager::getIns().getVisionLocation(VLName::DispenDownLookLocation);
    upLookCameraLocation = VisionManager::getIns().getVisionLocation(VLName::UpLookCameraLocation);

    lensPrLocation = VisionManager::getIns().getVisionLocation(VLName::LensPrLocation);
    senserPrLocation = VisionManager::getIns().getVisionLocation(VLName::SenserPrLocation);

    glueParthCalibration = VisionManager::getIns().getCalibration(CaliName::ShotterDownLookCameraCalibration);

    dispenser->init(sUTXYZ->xAxis(), sUTXYZ->yAxis(), sUTXYZ->zAxis(), shotGlueOut);
}

void AaHead::startEventHandle(const WorkerEvent &event)
{
    Q_UNUSED(event)
    isAaHeadStopped = false;
    pushEvent(WorkerEvent("startAuto"));
}

void AaHead::allWorkerStopped()
{
    isAaHeadStopped = true;
}

void AaHead::purgeEventHandle()
{
    purgeEventHandled();
}

void AaHead::resetEventHandle()
{
    isAaHeadStopped = false;
}

void AaHead::homeWorker(bool moveToReadyPosAfterHome)
{
    sUTXYZ->zAxis()->home();

    aAThetaXYZ->xAxis()->home(false);
    aAThetaXYZ->yAxis()->home(false);
    aAThetaXYZ->zAxis()->home(false);

    sUTXYZ->xAxis()->home(false);
    sUTXYZ->yAxis()->home();

    aAThetaXYZ->xAxis()->waitHomeDone();
    aAThetaXYZ->yAxis()->waitHomeDone();
    aAThetaXYZ->zAxis()->waitHomeDone();

    sUTXYZ->xAxis()->waitHomeDone();

    if (moveToReadyPosAfterHome)
    {
        moveToStanbyPos();
    }
}

void AaHead::moveToStanbyPos()
{
    aAThetaXYZ->moveTo(XYZPosName::StandbyPos);
    sUTXYZ->moveTo(XYZPosName::StandbyPos);
}

bool AaHead::glueCheck(QImage &imageBefore, QImage &imageAfter)
{
    auto glueCheckParam = aaHeadConfig->glueCheckParam();
    QImage resultImage;
    double outMaxGlueWidth = 0;
    double outMinGlueWidht = 0;
    double outAveGlueWidth = 0;
    bool res
        = VisionManager::getIns().vision()->glueCheck(imageBefore, imageAfter, glueCheckParam->resoultion(),
                                                      resultImage, outMinGlueWidht, outMaxGlueWidth, outAveGlueWidth);
    if (res)
    {
        shotGlueDotPrLocation->tryShowImage(resultImage);
        if (outMaxGlueWidth <= glueCheckParam->maxGlueWidth() && outMinGlueWidht >= glueCheckParam->minGlueWidth()
            && outAveGlueWidth >= glueCheckParam->aveGlueWidthLowerLimit()
            && outAveGlueWidth <= glueCheckParam->aveGlueWidthUpperLimit())
        {
            return true;
        }
        else
        {
            qCInfo(logCate()) << tr("Judge glue width failed! Glue width limit: [%1, %2], real glue width range: [%3, "
                                    "%4].\r\n"
                                    "Average glue width limit: [%5, %6], average glue width: %7")
                                     .arg(glueCheckParam->minGlueWidth())
                                     .arg(glueCheckParam->maxGlueWidth())
                                     .arg(outMinGlueWidht)
                                     .arg(outMaxGlueWidth)
                                     .arg(glueCheckParam->aveGlueWidthLowerLimit())
                                     .arg(glueCheckParam->aveGlueWidthUpperLimit())
                                     .arg(outAveGlueWidth);
            return false;
        }
    }
    else
    {
        qCWarning(logCate()) << tr("Execute glue check failed!");
        shotGlueDotPrLocation->tryShowImage(imageAfter);
        return false;
    }
}

void AaHead::pickLens()
{
    if (aaHeadConfig->isDryRun())
    {
        return;
    }

    aaGripper->set(true);
    if (aaHeadConfig->gripLensDelay() > 0)
    {
        QThread::msleep(aaHeadConfig->gripLensDelay());
    }
    lUTVacuum->set(false);
}

// calibrate

void AaHead::calibrateShotterToDownLookCameraOffset()
{
    auto shotGlueDotPos = sUTXYZ->getPos<XYZModulePos>(XYZPosName::ShotGlueDotPos);
    double currentX = sUTXYZ->xAxis()->getFeedbackPos();
    double currentY = sUTXYZ->yAxis()->getFeedbackPos();

    double offsetX = shotGlueDotPos->xPos() - currentX;
    double offsetY = shotGlueDotPos->yPos() - currentY;

    auto res = UIOperation::getIns()->yesNoConfirm(tr("calibrateShotterToCameraTipOffset successful!\r\nOffset x: "
                                                      "%1, Offset y: %2\r\nWould you like to apply this offset?")
                                                       .arg(offsetX)
                                                       .arg(offsetY));
    if (res)
    {
        aaHeadConfig->setShotterTopToCameraOffsetX(offsetX);
        aaHeadConfig->setShotterTopToCameraOffsetY(offsetY);
    }
}

void AaHead::shotGlueDot()
{
    sUTXYZ->moveToPos(XYZPosName::ShotGlueDotPos, XYZModulePos::ZS_XY_Z);

    shotGlueOut->set(true);
    QThread::msleep(aaHeadConfig->shotGlueDotTime());
    shotGlueOut->set(false);

    sUTXYZ->moveToPos(XYZPosName::GluePrPos, XYZModulePos::ZS_XY_Z);
}

QString AaHead::getDispensePathResultImageName()
{
    QString resultImageName = aaHeadConfig->dispenseParthFileName().replace(".avdata", ".jpg");
    resultImageName = dispensePathDir() + resultImageName;
    if (QFile::exists(resultImageName))
    {
        return QString("file:///") + QFileInfo(resultImageName).absoluteFilePath();
    }
    else
    {
        return "";
    }
}

void AaHead::saveImageForEditDispPath()
{
    checkIsInit();
    shotGlueDotPrLocation->camera()->saveImage(dispensePathDir(), "dispensePath.jpg");
    UIOperation::getIns()->showTip(tr("Save image to %1dispensePath.jpg").arg(dispensePathDir()));
}

void AaHead::moveToUpDownLookPrPos()
{
    checkIsInit();

    sUTXYZ->moveTo(XYZPosName::UpLookAndDownLookPrPos);
}

void AaHead::excuteUpDownLookClibrate()
{
    checkIsInit();
    PrOffset upLookOffset;
    if (!upLookCameraLocation->performPR(upLookOffset))
    {
        throw SilicolAbort(tr("Perform Up Look Camera Location pr failed!"));
    }

    PrOffset downLookOffset;
    if (!shotGlueDotPrLocation->performPR(downLookOffset))
    {
        throw SilicolAbort(tr("Perform Down Look Camera Location pr failed!"));
    }

    double offsetX = downLookOffset.X - upLookOffset.X;
    double offsetY = downLookOffset.Y - upLookOffset.Y;
    double offsetTheta = downLookOffset.Theta + upLookOffset.Theta;

    auto res = UIOperation::getIns()->yesNoConfirm(
        tr("calibrateDownLookToUpLookCameraOffset successful!\r\nOffset x: "
           "%1, Offset y: %2, Offset Theta: %3\r\nWould you like to apply this offset?")
            .arg(offsetX)
            .arg(offsetY)
            .arg(offsetTheta));
    if (res)
    {
        aaHeadConfig->setUpLookCameraToDownLookCameraOffsetX(offsetX);
        aaHeadConfig->setUpLookCameraToDownLookCameraOffsetY(offsetY);
        aaHeadConfig->setUpLookCameraToDownLookCameraOffsetTheta(offsetTheta);
    }
}

void AaHead::calibrateDownLookToUpLookCameraOffset()
{
    moveToUpDownLookPrPos();
    excuteUpDownLookClibrate();
}

// manual
void AaHead::pickLensManual()
{
    checkIsInit();
    grabLens();
}

void AaHead::placeRejectLensManual()
{
    checkIsInit();

    placeNgLensToLUT();
}

// auto run
void AaHead::startAuto()
{
    checkIsInit();
    QVariantList arg;
    arg << AAResult::FirstLoad;
    pushEvent(WorkerEvent("sendResultToPA", arg));
}

void AaHead::sendResultToPA(QString type)
{
    sUTXYZ->moveTo(XYZPosName::LoadMaterialPos);

    QVariantList arg;
    arg << type;
    postEvent(WorkerName::PickArm, WorkerEvent("placeMaterial", arg));
}

void AaHead::AAHeadRun(QString type)
{
    if (type == AAResult::FirstLoad || type == AAResult::GoodProduct || type == AAResult::NgProduct)
    {
        pushEvent(WorkerEvent("doSensorPr"));
        pushEvent(WorkerEvent("grabLens"));
        pushEvent(WorkerEvent("doLensPr"));
        pushEvent(WorkerEvent("roughAA"));
        pushEvent(WorkerEvent("findBestPos"));
    }
    else if (type == AAResult::NgLens)
    {
        pushEvent(WorkerEvent("grabLens"));
        pushEvent(WorkerEvent("doLensPr"));
        pushEvent(WorkerEvent("roughAA"));
        pushEvent(WorkerEvent("findBestPos"));
    }
    else if (type == AAResult::NgSensor)
    {
        pushEvent(WorkerEvent("doSensorPr"));
        pushEvent(WorkerEvent("roughAA"));
        pushEvent(WorkerEvent("findBestPos"));
    }
    else
    {
        throw SilicolAbort(tr(" PA post to AA Head result Err!  err type: %1").arg(type));
    }
}

void AaHead::doSensorPr()
{
    try
    {
        sUTXYZ->moveToPos(XYZPosName::GluePrPos, XYZModulePos::ZS_XY_Z, true);

        if (!aaHeadConfig->isDryRun())
        {
            if (!senserPrLocation->performPR(downlookCalculateOffset))
            {
                throw SilicolAbort("calculate senser offset failed!");
            }
        }
    }
    catch (SilicoolException &se)
    {
        auto res = UIOperation::getIns()->yesNoConfirm(tr("excute Sensor fail, would you like to retry?"));
        if (res)
        {
            pushEvent(WorkerEvent("doSensorPr", QVariantList(), 2000));
        }
        else
        {
            clearEvent();

            QVariantList arg;
            arg << AAResult::NgSensor;
            pushEvent(WorkerEvent("sendResultToPA", arg));
        }
    }
}

void AaHead::grabLens()
{
    try
    {
        sUTXYZ->moveZToPos(XYZPosName::StandbyPos);
        aAThetaXYZ->moveTo(XYZPosName::PickLensPos);
        sUTXYZ->moveXYToPos(XYZPosName::PickLensPos);

        if (aaGripper->get())
        {
            GripperGetLensErr err;
            auto option = ErrorHandler::getErrorHandlingOption(err);

            if(option == ErrorHandlingOption::Extend_)
            {
                aaGripper->set(false);
            }
            else {
                throw SilicolAbort(tr("Pick lens Failed"));
            }
        }

        sUTXYZ->zAxis()->softLandPosDown(SLPos::PickLens);
        sUTXYZ->zAxis()->relMove(-0.001, true);

        if(aaHeadConfig->gripLensDelay() > 0)
        {
            QThread::msleep(aaHeadConfig->gripLensDelay());
        }

        if (!aaHeadConfig->isDryRun())
        {
            pickLens();
        }
        sUTXYZ->moveZToPos(XYZPosName::StandbyPos);
    }
    catch (SilicoolException &se)
    {
        auto res = UIOperation::getIns()->yesNoConfirm(tr("Pick lens Failed, would you like to retry?"));
        if (res)
        {
            pushEvent(WorkerEvent("grabLens", QVariantList(), 2000));
        }
        else
        {
            clearEvent();
            placeNgLensToLUT();
            sUTXYZ->moveZToPos(XYZPosName::StandbyPos);

            QVariantList arg;
            arg << AAResult::NgLens;
            pushEvent(WorkerEvent("sendResultToPA", arg));
        }
    }
}

void AaHead::doLensPr()
{
    try
    {
        sUTXYZ->moveTo(XYZPosName::ULPrGripPos);
        aAThetaXYZ->moveTo(XYZPosName::MushroomPos);

        if (!aaHeadConfig->isDryRun())
        {
            if (!lensPrLocation->performPR(uplookCalculateOffset))
            {
                throw SilicolAbort("calculate lens offset failed!");
            }
        }
    }
    catch (SilicoolException &se)
    {
        auto res = UIOperation::getIns()->yesNoConfirm(tr("Excute lens pr Failed, would you like to retry?"));
        if (res)
        {
            pushEvent(WorkerEvent("doLensPr", QVariantList(), 2000));
        }
        else
        {
            clearEvent();
            placeNgLensToLUT();

            QVariantList arg;
            arg << AAResult::NgLens;
            pushEvent(WorkerEvent("sendResultToPA", arg));
        }
    }
}

void AaHead::roughAA()
{
    moveToMushroomPosWithOffset();
}

void AaHead::findBestPos()
{
    if (!aaHeadConfig->isDryRun())
    {
        //Reset the AA Result as Raw Sensor & Raw Lens & No Product
        postEvent(WorkerName::AACore, WorkerEvent("resetAAResultCurrentUnitToRaw"));
        //Run Flowchart
        postEvent(WorkerName::AACore, WorkerEvent("runAAFlowchart"));
    }
    else
    {
        QVariantList arg;
        arg << false;
        pushEvent(WorkerEvent("moveToShotGlue", arg));
        pushEvent(WorkerEvent("moveBackToBestPos"));
        pushEvent(WorkerEvent("assemblyProduct"));
        pushEvent(WorkerEvent("doUV"));

        QVariantList arg2;
        arg2 << AAResult::GoodProduct;
        pushEvent(WorkerEvent("sendResultToPA", arg2));
    }
}

void AaHead::aaFinish()
{
    qCInfo(logCate()) << "receiveAAFlowchartFinish";
    if (aaCore != Q_NULLPTR)
    {
        AAResultStruct aaResult = aaCore->getAAResultCurrentUnit();
        qCInfo(logCate()) << "AAResult SensorState: " << aaResult.sensorState << " LensState: " << aaResult.lensState
                          << " ProductState: " << aaResult.productState;
        /*
        if (aaResult.lensState == AAResult::NgLens)
        {
            clearEvent();
            placeNgLensToLUT();
            uplookCalculateOffset = PrOffset(0, 0, 0);

            QVariantList arg;
            arg << AAResult::NgLens;
            pushEvent(WorkerEvent("sendResultToPA", arg));
        }
        else if (aaResult.lensState == AAResult::NgSensor)
        {
            clearEvent();
            downlookCalculateOffset = PrOffset(0, 0, 0);

            QVariantList arg;
            arg << AAResult::NgSensor;
            pushEvent(WorkerEvent("sendResultToPA", arg));
        }
        else if (aaResult.lensState == AAResult::NgProduct)
        {
            clearEvent();
            uplookCalculateOffset = PrOffset(0, 0, 0);
            downlookCalculateOffset = PrOffset(0, 0, 0);

            aaGripper->set(false);
            sUTXYZ->moveZToPos(XYZPosName::StandbyPos);
            QVariantList arg;
            arg << AAResult::NgProduct;
            pushEvent(WorkerEvent("sendResultToPA", arg));
        }
        else if (aaResult.lensState == AAResult::GoodProduct)
        */
        {
            clearEvent();

            uplookCalculateOffset = PrOffset(0, 0, 0);
            downlookCalculateOffset = PrOffset(0, 0, 0);

            aaGripper->set(false);
            sUTXYZ->moveZToPos(XYZPosName::StandbyPos);

            QVariantList arg;
            arg << AAResult::GoodProduct;
            pushEvent(WorkerEvent("sendResultToPA", arg));
        }
    }
}

void AaHead::moveToMushroomPosWithOffset()
{
    aAThetaXYZ->moveTo(XYZPosName::MushroomPos);

    if (!aaHeadConfig->isDryRun())
    {
        auto mushroomPos = sUTXYZ->getPos<XYZModulePos>(XYZPosName::MushroomPos);

        XYZModulePos mushroomPosWithOffset;
        double thetaOffset = aaHeadConfig->upLookCameraToDownLookCameraOffsetTheta()
                - (uplookCalculateOffset.Theta - downlookCalculateOffset.Theta);

        if(aaHeadConfig->useXYOffset())
        {
            mushroomPosWithOffset.setXPos(mushroomPos->xPos() + aaHeadConfig->upLookCameraToDownLookCameraOffsetX()
                                          + (uplookCalculateOffset.X - downlookCalculateOffset.X));
            mushroomPosWithOffset.setYPos(mushroomPos->yPos() + aaHeadConfig->upLookCameraToDownLookCameraOffsetY()
                                          + (uplookCalculateOffset.Y - downlookCalculateOffset.Y));
        }
        else
        {
            mushroomPosWithOffset.setXPos(mushroomPos->xPos());
            mushroomPosWithOffset.setYPos(mushroomPos->yPos());
        }

        sUTXYZ->moveZToPos(XYZPosName::StandbyPos);
        sUTXYZ->moveXY(mushroomPosWithOffset.xPos(), mushroomPosWithOffset.yPos());

        if(aaHeadConfig->useThetaOffset())
        {
            aAThetaXYZ->zAxis()->relMove(thetaOffset);
        }

        sUTXYZ->moveZToPos(XYZPosName::MushroomPos);

        return;
    }

    sUTXYZ->moveTo(XYZPosName::MushroomPos);
}

void AaHead::executeGlue(QVector<PathEndPoint> &dispensePath)
{
    if (dispensePath.length() < 3)
    {
        throw SilicolAbort(tr("dispensePath size is too small! Size: %1").arg(dispensePath.length()), EX_LOCATION);
    }

    bestPos.setXPos(sUTXYZ->xAxis()->getFeedbackPos());
    bestPos.setYPos(sUTXYZ->yAxis()->getFeedbackPos());
    bestPos.setZPos(sUTXYZ->zAxis()->getFeedbackPos());

    double readyForDispenseHeight = dispensePath[0].z;

    sUTXYZ->moveZToPos(XYZPosName::StandbyPos);

    sUTXYZ->moveXY(dispensePath[0].x, dispensePath[0].y);
    sUTXYZ->xAxis()->waitArrivedPos(dispensePath[0].x, 0.002);
    sUTXYZ->yAxis()->waitArrivedPos(dispensePath[0].y, 0.002);
    sUTXYZ->zAxis()->absMove(readyForDispenseHeight, true);

    try
    {
        dispenser->dispensePath(dispensePath);
        sUTXYZ->moveZToPos(XYZPosName::StandbyPos);

        sUTXYZ->moveXY(bestPos.xPos(), bestPos.yPos());
        sUTXYZ->xAxis()->waitArrivedPos(bestPos.xPos(), 0.002);
        sUTXYZ->yAxis()->waitArrivedPos(bestPos.yPos(), 0.002);

        sUTXYZ->zAxis()->absMove(bestPos.zPos());
        sUTXYZ->zAxis()->waitArrivedPos(bestPos.zPos(), 0.001);
    }
    catch (SilicoolException &se)
    {
        shotGlueOut->set(false);
        sUTXYZ->moveZToPos(XYZPosName::StandbyPos);
        throw se;
    }
}

void AaHead::moveBackToBestPos()
{
    if (aaHeadConfig->isDryRun())
    {
        sUTXYZ->moveTo(XYZPosName::MushroomPos);
        return;
    }

    sUTXYZ->moveZToPos(XYZPosName::StandbyPos);
    sUTXYZ->moveXY(bestPos.xPos(), bestPos.yPos());

    sUTXYZ->zAxis()->absMove(bestPos.zPos());
}

void AaHead::assemblyProduct()
{
    if (aaHeadConfig->isDryRun())
    {
        return;
    }

    if (!aaGripper->get())
    {
        throw SilicolAbort(tr("Gripper missed lens, please check and get an new one !"));
    }
    auto AssemblyZPos = sUTXYZ->getPos<XYZModulePos>(XYZPosName::AssemblyPos);
    if (AssemblyZPos->zPos() > bestPos.zPos())
    {
        sUTXYZ->zAxis()->absMove(AssemblyZPos->zPos());
    }
    else
    {
        sUTXYZ->zAxis()->absMove(bestPos.zPos());
    }

    if (aaHeadConfig->assemblyDelay() > 0)
    {
        QThread::msleep(aaHeadConfig->assemblyDelay());
    }
}

void AaHead::doUV()
{
    if (!aaHeadConfig->isDryRun())
    {
        uVOut->set(true);
        QThread::msleep(100);
        uVOut->set(false);
        QThread::msleep(aaHeadConfig->actionUVTime());
        uVOut->set(true);
        QThread::msleep(100);
        uVOut->set(false);
    }
}

void AaHead::placeNgLensToLUT()
{
    sUTXYZ->moveZToPos(XYZPosName::StandbyPos);

    sUTXYZ->moveTo(XYZPosName::RejectLensPos);

    /* to do for hardware fixing
    sUTXYZ->moveXYToPos(XYZPosName::RejectLensPos);

    sUTXYZ->zAxis()->softLandPosDown(SLPos::PickRejectSensor);
    sUTXYZ->zAxis()->relMove(0.01, true);
    */

    aaGripper->set(false);
    if (aaHeadConfig->extendGripperDelay() > 0)
    {
        QThread::msleep(aaHeadConfig->extendGripperDelay());
    }

    // to do for hardware fixing
    //lUTRejectVacuumGet();
}

void AaHead::lUTRejectVacuumGet()
{
    LUTRejectVacuum->set(true);
    if (aaHeadConfig->setVacuumDelay() > 0)
    {
        QThread::msleep(aaHeadConfig->setVacuumDelay());
    }

    try
    {
        if (!LUTRejectVacuum->get())
        {
            throw SilicolAbort(tr("LUT reject vacuum get reject lens failed ! would you like to retry?"));
        }
    }
    catch (SilicoolException &se)
    {
        auto res = UIOperation::getIns()->okCancelConfirm(se.what());
        if (res)
        {
            lUTRejectVacuumGet();
        }
    }
}

QVector<PathEndPoint> AaHead::mapDispensePath(PrOffset prGluePos, double shotGlueHeight)
{
    QVector<PathEndPoint> dispensePath;
    auto currentPos = sUTXYZ->getPos<XYZModulePos>(XYZPosName::GluePrPos);

    double theta = (prGluePos.Theta - aaHeadConfig->shotterTopToCameraOffsetT()) * M_PI / 180;
    for (int i = 0; i < mechDispPath.size(); ++i)
    {
        double x = mechDispPath[i].x();
        double y = mechDispPath[i].y();
        double mappedX = x * cos(theta) - y * sin(theta) + prGluePos.X + aaHeadConfig->shotterTopToCameraOffsetX()
                         + currentPos->xPos();
        double mappedY = y * cos(theta) + x * sin(theta) + prGluePos.Y + aaHeadConfig->shotterTopToCameraOffsetY()
                         + currentPos->yPos();

        dispensePath.push_back(
            PathEndPoint(mappedX, mappedY, shotGlueHeight - aaHeadConfig->shotGlueOffsetZ(), LinePath));
    }
    return dispensePath;
}

void AaHead::readDispensePath()
{
    if (glueParthCalibration == nullptr)
    {
        throw SilicolAbort("glueParthCalibration is null!");
    }
    QString fileName = dispensePathDir() + aaHeadConfig->dispenseParthFileName();
    if (!QFile::exists(fileName))
    {
        throw SilicolAbort(tr("Dispense path file not exist! FileName: %1").arg(fileName));
    }
    try
    {
        QVector<QPointF> pixelPath = VisionManager::getIns().vision()->readDispensePath(fileName);
        mechDispPath.clear();
        foreach (auto point, pixelPath)
        {
            QPointF mechPoint;
            if (!glueParthCalibration->getDeltaDistanceFromCenter(point, mechPoint))
            {
                throw SilicolAbort("glueParthCalibration is not inited!", EX_LOCATION);
            }
            mechDispPath.push_back(QPointF(mechPoint.x(), mechPoint.y()));
        }
    }
    catch (SilicoolException &se)
    {
        throw se;
    }
}

void AaHead::moveToShotGlue(bool doGlueCheck)
{
    checkIsInit();
    readDispensePath();

    QImage imageBefore;
    if (doGlueCheck)
    {
        imageBefore = shotGlueDotPrLocation->getImage();
    }

    auto dispensePath = mapDispensePath(downlookCalculateOffset, aaHeadConfig->shotterSoftLandHeight());

    executeGlue(dispensePath);

    if (doGlueCheck)
    {
        sUTXYZ->moveToPos(XYZPosName::GluePrPos, XYZModulePos::ZS_XY_Z);
        QImage imageAfter = shotGlueDotPrLocation->getImage();
        glueCheck(imageBefore, imageAfter);
    }
}

void AaHead::testCmd()
{
    qCInfo(logCate()) << "test cmd";
    findBestPos();
}

void AaHead::prToBond()
{
    doSensorPr();
    doLensPr();

    moveToMushroomPosWithOffset();
}

void AaHead::CalGripperPos(int pos)
{
    QString posName = "";
    QString prPosName = "";

    PrOffset downLOffset;
    PrOffset upLOffset;

    auto uDLookCalibPos = sUTXYZ->getPos<XYZModulePos>(XYZPosName::UpLookAndDownLookPrPos);

    auto uLGripperPos = sUTXYZ->getPos<XYZModulePos>(XYZPosName::ULPrGripPos);

    switch (pos)
    {
        case 1:
            posName = "PickLensPos";
            prPosName = XYZPosName::DLPrLutPos;
            break;
        case 2:
            posName = "RejectLensPos";
            prPosName = XYZPosName::DLPrRLutPos;
            break;
        case 3:
            posName = "MushroomPos";
            prPosName = XYZPosName::DLPrSutPos;
            break;
        defaul:
            break;
    }

    auto dLPrPos = sUTXYZ->getPos<XYZModulePos>(prPosName);

    // calcilate pos = ULpos + 2CameraOffset + (2CameraPrPos - meedCalculatePos)
    double xPos = uLGripperPos->xPos() - aaHeadConfig->upLookCameraToDownLookCameraOffsetX()
                  - (uDLookCalibPos->xPos() - dLPrPos->xPos());
    double yPos = uLGripperPos->yPos() - aaHeadConfig->upLookCameraToDownLookCameraOffsetY()
                  - (uDLookCalibPos->yPos() - dLPrPos->yPos());

    UIOperation::getIns()->yesNoConfirm(tr("Calculate %1 pos successful!.\r\n xPos: "
                                           "%3, yPos: %4 .\r\n please ensure and copy to %2 setting than save")
                                            .arg(posName)
                                            .arg(posName)
                                            .arg(xPos)
                                            .arg(yPos));
}

void AaHead::shotGlueLine(double lineLen)
{
    checkIsInit();

    double currentX = sUTXYZ->xAxis()->getFeedbackPos();
    double currentY = sUTXYZ->yAxis()->getFeedbackPos();
    auto standbyPos = sUTXYZ->getPos<XYZModulePos>(XYZPosName::StandbyPos);
    auto shotGlueDotPos = sUTXYZ->getPos<XYZModulePos>(XYZPosName::ShotGlueDotPos);
    double y1 = currentY - lineLen / 2;
    double y2 = currentY + lineLen / 2;
    double shotGlueHeight = shotGlueDotPos->zPos() + aaHeadConfig->shotGlueOffsetZ();
    double safetyZHeight = standbyPos->zPos();

    dispenser->dispenseLine(QPointF(currentX, y1), QPointF(currentX, y2), shotGlueHeight, safetyZHeight);
}

void AaHead::shotRectangle(double width, double height)
{
    checkIsInit();

    auto standbyPos = sUTXYZ->getPos<XYZModulePos>(XYZPosName::StandbyPos);
    auto shotGlueDotPos = sUTXYZ->getPos<XYZModulePos>(XYZPosName::ShotGlueDotPos);
    double currentX = sUTXYZ->xAxis()->getFeedbackPos();
    double currentY = sUTXYZ->yAxis()->getFeedbackPos();
    double shotGlueHeight = shotGlueDotPos->zPos() + aaHeadConfig->shotGlueOffsetZ();

    dispenser->dispenseRect(QPointF(currentX, currentY), width, height, shotGlueHeight, standbyPos->zPos());
}

void AaHead::shotGlue(bool check)
{
    doSensorPr();
    moveToShotGlue(check);
}
